package com.xwaf.platform.web.filter.xss;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * 
 * <p>
 * 防止sql注入,xss攻击 前端可以对输入信息做预处理，后端也可以做处理。
 * <p>
 * 
 * @author 李聪 <br>
 * @email xwaf_love@yeah.net <br>
 * @since JDK 1.8<br>
 * @date 2020年1月1日 上午10:54:03 <br>
 * @see 无<br>
 *      Copyright (c) 2020, xwaf_love@yeah.net All Rights Reserved.<br>
 */
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {

	protected Logger logger = LoggerFactory.getLogger(getClass());
	private static String key = "and|exec|insert|select|delete|update|count|*|%|chr|mid|master|truncate|char|declare|;|or|-|+";
	private static Set<String> notAllowedKeyWords = new HashSet<String>(0);
	private static String replacedString = "INVALID";
	static {
		String keyStr[] = key.split("\\|");
		for (String str : keyStr) {
			notAllowedKeyWords.add(str);
		}
	}

	private String currentUrl;

	public XssHttpServletRequestWrapper(HttpServletRequest servletRequest) {
		super(servletRequest);
		currentUrl = servletRequest.getRequestURI();
	}

	/**
	 * 覆盖getParameter方法，将参数名和参数值都做xss过滤。<br>
	 * 如果需要获得原始的值，则通过super.getParameterValues(name)来获取<br>
	 * getParameterNames,getParameterValues和getParameterMap也可能需要覆盖
	 */
	@Override
	public String getParameter(String parameter) {
		String value = super.getParameter(parameter);
		if (value == null) {
			return null;
		}
		return cleanXSS(value);
	}

	@Override
	public String[] getParameterValues(String parameter) {
		String[] values = super.getParameterValues(parameter);
		if (values == null) {
			return null;
		}
		int count = values.length;
		String[] encodedValues = new String[count];
		for (int i = 0; i < count; i++) {
			encodedValues[i] = cleanXSS(values[i]);
		}
		return encodedValues;
	}

	@Override
	public Map<String, String[]> getParameterMap() {
		Map<String, String[]> values = super.getParameterMap();
		if (values == null) {
			return null;
		}
		Map<String, String[]> result = new HashMap<>();
		for (String key : values.keySet()) {
			String encodedKey = cleanXSS(key);
			int count = values.get(key).length;
			String[] encodedValues = new String[count];
			for (int i = 0; i < count; i++) {
				encodedValues[i] = cleanXSS(values.get(key)[i]);
			}
			result.put(encodedKey, encodedValues);
		}
		return result;
	}

	/**
	 * 覆盖getHeader方法，将参数名和参数值都做xss过滤。 <br>
	 * 如果需要获得原始的值，则通过super.getHeaders(name)来获取 getHeaderNames 也可能需要覆盖
	 */
	@Override
	public String getHeader(String name) {
		String value = super.getHeader(name);
		if (value == null) {
			return null;
		}
		return cleanXSS(value);
	}

	private String cleanXSS(String valueP) {
		// You'll need to remove the spaces from the html entities below
		String value = valueP.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
		value = value.replaceAll("<", "& lt;").replaceAll(">", "& gt;");
		value = value.replaceAll("\\(", "& #40;").replaceAll("\\)", "& #41;");
		value = value.replaceAll("'", "& #39;");
		value = value.replaceAll("eval\\((.*)\\)", "");
		value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
		value = value.replaceAll("script", "");
		value = cleanSqlKeyWords(value);
		return value;
	}

	private String cleanSqlKeyWords(String value) {
		String paramValue = value;
		for (String keyword : notAllowedKeyWords) {
			if (paramValue.length() > keyword.length() + 4 && (paramValue.contains(" " + keyword)
					|| paramValue.contains(keyword + " ") || paramValue.contains(" " + keyword + " "))) {
				paramValue = StringUtils.replace(paramValue, keyword, replacedString);
				logger.error(this.currentUrl + "已被过滤，因为参数中包含不允许sql的关键词(" + keyword + ")" + ";参数：" + value + ";过滤后的参数："
						+ paramValue);
			}
		}
		return paramValue;
	}
}
